#pragma semicolon 1
#include <sourcemod>
#include <colors>
#define    PLUGIN_VERSION    "1.0.2"
#define CVAR_FLAGS FCVAR_PLUGIN|FCVAR_NOTIFY

new round_show = 1;

public Plugin:myinfo = 
{
    name = "L4D(2) Reserved Slots",
    author = "Yd社区",
    description = "L4D2会员通道",
    version = PLUGIN_VERSION,
    url = "http://www.l4d2.com/"
};

//#define MSG_KICK_REASON    "你占用了Yd会员通道,\r\n满足以下条件享受会员保护机制：\n1.进丫蛋服请上YY:72806 \n2.满人情况会优先让带[Yd]马甲会员进入服务器"
#define MSG_KICK_REASON    "进丫蛋服请上YY:72806.满人情况会优先让带[Yd]马甲会员进入服务器"
#define MSG_KICK_FALSE    "服务器内全部丫蛋会员,无法进入,服务器已满!"

static    MaxPlayer,
Handle:L4dtoolzExtension = INVALID_HANDLE,
Handle:DowntownExtension = INVALID_HANDLE,
Handle:cvarReservedSlots = INVALID_HANDLE;

new kick_client_team;

    
/* 注释 - 检测游戏L4D/L4D2 */
public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
{
    decl String:game_name[64];
    GetGameFolderName(game_name, sizeof(game_name));
    if (!StrEqual(game_name, "left4dead", false) && !StrEqual(game_name, "left4dead2", false))
    {
        Format(error, err_max, "Plugin supports Left4Dead and Left4Dead 2 only.");
        return APLRes_Failure;
    }
    return APLRes_Success;
}

public OnPluginStart()
{
    
    L4dtoolzExtension = FindConVar("sv_maxplayers");
    DowntownExtension = FindConVar("l4d_maxplayers");
    
    
    CreateConVar("l4d_reservedslots_version", PLUGIN_VERSION, "Version", CVAR_FLAGS|FCVAR_SPONLY|FCVAR_DONTRECORD);
    cvarReservedSlots = CreateConVar("l4d_reserved_slots", "1", "满人后预留几个通道给队员 0 = 关闭", CVAR_FLAGS, true, 0.0);
    
    HookEvent("round_start", Event_Round_Start);
    HookEvent("round_end", Event_REnd);
    //AutoExecConfig(true, "l4d_reservedslots");  
	
	//RegConsoleCmd("sm_kid", MKickID);// 菜单显示
	
	
    round_show = 1;
}

/* 设定预留通到 */
public OnConfigsExecuted()
{
    if (DowntownExtension != INVALID_HANDLE)
    {
        MaxPlayer = GetConVarInt(DowntownExtension);
    }
    else if (L4dtoolzExtension != INVALID_HANDLE || (L4dtoolzExtension != INVALID_HANDLE && DowntownExtension != INVALID_HANDLE))
    {
        MaxPlayer = GetConVarInt(L4dtoolzExtension);
    }
}

public Action:Event_Round_Start(Handle:event, String:event_name[], bool:dontBroadcast)
{
    CreateTimer(80.0, MakePlayerMore);
}

// 回合结束踢出旁观
public Action:Event_REnd(Handle:event, String:event_name[], bool:dontBroadcast)
{    
    if(round_show)
    {
        CreateTimer(0.1, CheckMyTeamSp);   
        round_show = 0;
    }    
}
public Action:MKickID(iCid, args)
{
	decl String:arg[4];
	GetCmdArg(1, arg, sizeof(arg));
	new amount = StringToInt(arg);
		
	PrintToChat(iCid, "ID __ %d __%d, %N", iCid, amount, amount);
		
	ServerCommand("kickid %d \"%s\"", GetClientUserId(amount), MSG_KICK_REASON);
}

/* 当玩家连接游戏 */
//public OnClientConnected(client)
public bool:OnClientConnect(client)
{
    if (IsFakeClient(client))
        return true;

    /* 检测 */

    //new inConn = GetRealClientCount(0);
    //new inGameCl = GetRealClientCount(1);
    //PrintToChatAll("connect_当前连接数 %d, 当前玩家数 %d!", inConn, inGameCl);    
    if(GetRealClientCount(0) > MaxPlayer)
    {
        //PrintToChatAll("connect_当前连接数%d, 当前玩家数%d!", GetRealClientCount(0), GetRealClientCount(1));
        if (CheckNameIsOk(client))
        {
            if (!KickFalseNamePlayer())
            {
                //CPrintToChatAll("{default}当前没有不符合的玩家，玩家 {green}%N {default}未能进入服务器!", client);
                //LogMessage("kick_TTT当前没有不符合的玩家，玩家 %N 未能进入服务器!", client);
                //KickClient(client, MSG_KICK_FALSE);
				ServerCommand("kickid %d \"%s\"", GetClientUserId(client), MSG_KICK_FALSE);
				//ServerCommand(MSG_KICK_FALSE, client);	
                //return false;
            }
            else
            {
                //CPrintToChatAll("{default}踢出玩家成功，玩家 {green}%N {default}进入服务器!", client);
                //LogMessage("connect_TTTT踢出玩家成功，玩家 %N 进入服务器!", client);
                return true;
            }
        }
        else
        {
            //CPrintToChatAll("{default}玩家名不符合要求，玩家 {green}%N {default}未能通过会员通道进入服务器!", client);
            //LogMessage("kick_TTTT玩家名不符合要求，玩家 %N 未能通过会员通道进入服务器!", client);
            //KickClient(client, MSG_KICK_REASON);
			ServerCommand("kickid %d \"%s\"", GetClientUserId(client), MSG_KICK_REASON);
			//ServerCommand(MSG_KICK_REASON, client);	
            //return false;
        }
    }
    else
    {
        //PrintToChatAll("TEST_玩家【%N】进入成功", client);
        //LogMessage("connect_TTTT【%N】进入成功", client);
        return true;
    }
    return true;
}
// 进入游戏后检查旁观情况，旁观则T出
public OnClientPutInServer(client)
{
    CreateTimer(8.0, CheckMyTeam, client);
}

// 玩家进入游戏后检测队伍,如果旁观检测
public Action:CheckMyTeam(Handle:Timer, any:client)
{    
    if(IsValidPlayer(client, false))
    {        
        if(GetClientTeam(client) == 1 && IsServerFull())
        {// 旁观
            //CPrintToChatAll("{default}旁观者{green} %N {default}尝试进入", client);
            if (CheckNameIsOk(client))
            {
                if(!KickFalseNamePlayer())
                {
                    CPrintToChatAll("{default}当前没有不符合的玩家，玩家 {green}%N {default}未能从旁观状态进入服务器!", client);
                    LogMessage("Kick_旁观_当前没有不符合的玩家，玩家 %N 未能进入服务器!", client);
                    //KickClient(client, MSG_KICK_FALSE);// 当前没有不符合的玩
					ServerCommand("kickid %d \"%s\"", GetClientUserId(client), MSG_KICK_FALSE);
					//ServerCommand(MSG_KICK_FALSE, client);	
                }
                else
                {
                    //PrintToChatAll("玩家【%N】进入", client);
                    //LogMessage("旁观_玩家【%N】进入!", client);
                    if(IsValidPlayer(client, false))
                    {
                        ChangeClientTeam(client, kick_client_team);// 进入被T人的队伍
                        LogMessage("旁观_玩家【%N】进入成功!", client);
                    }
                    else
                    {
                        LogMessage("旁观_玩家【%N】非正常玩家，未能进入!", client);
                    }
                }
            }
            else
            {
                //CPrintToChatAll("{default}玩家名不符合要求，玩家 {green}%N {default}未能通过会员通道进入服务器!", client);
                LogMessage("CheckMyTeam_玩家名不符合要求，玩家 %N 未能通过会员通道进入服务器!", client);
				ServerCommand("kickid %d \"%s\"", GetClientUserId(client), MSG_KICK_REASON);
                //KickClient(client, MSG_KICK_REASON);
				//ServerCommand(MSG_KICK_REASON, client);	
            }
        }
        else
        {
            //LogMessage("玩家 %N 队伍_%d", client, GetClientTeam(client));
        }
    }
}
// 回合结束查看时候有旁观
public Action:CheckMyTeamSp(Handle:Timer)
{   
    for(new i = 1; i <= MaxClients; i++)
    {
        if (IsValidPlayer(i, false))
        {
            if(GetClientTeam(i) == 1)
            {// 旁观              
                if (CheckNameIsOk(i))
                {
                    if(!KickFalseNamePlayer())
                    {
                        CPrintToChatAll("{default}当前没有不符合的玩家，玩家 {green}%N {default}未能从旁观状态进入服务器!", i);
                        LogMessage("Kick_回合结束旁观_当前没有不符合的玩家，玩家 %N 未能进入服务器!", i);
                        //KickClient(i, MSG_KICK_FALSE);// 当前没有不符合的玩
						ServerCommand("kickid %d \"%s\"", GetClientUserId(i), MSG_KICK_FALSE);
						//ServerCommand(MSG_KICK_FALSE, i);	
                    }
                    else
                    {
                        // PrintToChatAll("玩家【%N】进入!", i);
                        LogMessage("回合结束旁观_玩家【%N】进入!", i);                        
                        if(IsValidPlayer(i, false))
                        {
                            ChangeClientTeam(i, kick_client_team);// 进入被T人的队伍
                            LogMessage("回合结束旁观_玩家【%N】进入成功!", i);
                        }
                        else
                        {
                            LogMessage("回合结束旁观_玩家【%N】非正常玩家，未能进入!", i);
                        }
                    }
                }
                else
                {
                    // PrintToChatAll("玩家名不符合要求，玩家 %N 未能通过会员通道进入服务器!", i);
                    LogMessage("CheckMyTeamSp_玩家名不符合要求，玩家 %N 未能通过会员通道进入服务器!", i);
                    //KickClient(i, MSG_KICK_REASON);
					ServerCommand("kickid %d \"%s\"", GetClientUserId(i), MSG_KICK_REASON);
					//ServerCommand(MSG_KICK_REASON, i);	
                }  
            }
        }
    }
    CreateTimer(0.1, MakePlayerNormal);
}
// 增加人数
public Action:MakePlayerMore(Handle:Timer)
{
    new newValue, Slots = GetConVarInt(cvarReservedSlots);
    
    if (!Slots) 
        return;
    if (DowntownExtension != INVALID_HANDLE)
    {
        newValue = MaxPlayer + Slots;
        //PrintToChatAll("设定最大玩家数_ %d", newValue);
        //LogMessage("设定最大玩家数_ %d", newValue);
        SetConVarInt(DowntownExtension, newValue);
    }
    else if (L4dtoolzExtension != INVALID_HANDLE || (L4dtoolzExtension != INVALID_HANDLE && DowntownExtension != INVALID_HANDLE))
    {
        newValue = MaxPlayer + Slots;
        //PrintToChatAll("设定最大玩家数__ %d", newValue);
        //LogMessage("设定最大玩家数__ %d", newValue);
        SetConVarInt(L4dtoolzExtension, newValue);
    }
    round_show = 1;
}
// 还原人数
public Action:MakePlayerNormal(Handle:Timer)
{
    new Slots = GetConVarInt(cvarReservedSlots);
    
    if (!Slots) return;
    if (DowntownExtension != INVALID_HANDLE)
    {
        //PrintToChatAll("还原最大玩家数_ %d", MaxPlayer);
        //LogMessage("还原最大玩家数_ %d", MaxPlayer);
        SetConVarInt(DowntownExtension, MaxPlayer);
    }
    else if (L4dtoolzExtension != INVALID_HANDLE || (L4dtoolzExtension != INVALID_HANDLE && DowntownExtension != INVALID_HANDLE))
    {
        //PrintToChatAll("还原最大玩家数__ %d", MaxPlayer);
        //LogMessage("还原最大玩家数__ %d", MaxPlayer);
        SetConVarInt(L4dtoolzExtension, MaxPlayer);
        //LogMessage("nromal_连接玩家 %d, 在游戏玩家 %d!", GetRealClientCount(0), GetRealClientCount(1)); 
    }
}

/* 踢出名字不合格玩家 */
public bool:KickFalseNamePlayer()
{
    for(new i = 1; i <= MaxClients; i++)
    {
        if (IsValidPlayer(i, false))
        {
            if (!CheckNameIsOk(i))
            {
                CPrintToChatAll("{default}玩家 {green}%N {default}名称不符合Yd会员要求，占用会员通道被踢出!", i);
                LogMessage("Kick_玩家 %N 占用会员通道或者名称不符合Yd会员要求被踢出!", i);
                kick_client_team = GetClientTeam(i);
                //KickClient(i, MSG_KICK_REASON);
				ServerCommand("kickid %d \"%s\"", GetClientUserId(i), MSG_KICK_REASON);
				//ServerCommand(MSG_KICK_REASON, i);	
                return true;
            }
        }
    }    
    return false;
}

/* 服务器是否已满 */
public bool:IsServerFull()
{
    new current = 0;    
    new max = MaxPlayer;
    //PrintToChatAll("最大玩家%d", max);
    for (new i=1; i<=MaxClients; i++)
    {
        if (IsValidPlayer(i))
            current++;
    }
    
    if (current >= max)
    {
        //PrintToChatAll("满服%d__%d", current, max);
        return true;
    }
    return false;
}

/* 检查名字是否合格 */
public bool:CheckNameIsOk(Client)
{   
    new String:username[32];
    new bool:IsOk = false;

    GetClientName(Client, username,sizeof(username));
    if (StrContains(username, "[Yd]", false) >= 0)
        IsOk = true;
    if (StrContains(username, "【Yd】", false) >= 0)
        IsOk = true;
    if (StrContains(username, "{Yd}", false) >= 0)
        IsOk = true;
    if (StrContains(username, "72806", false) >= 0)
        IsOk = true;
	if (StrContains(username, "丫蛋", false) >= 0)
        IsOk = true;

    return IsOk;
}

/* 判断玩家是否有效 */
stock bool:IsValidPlayer(Client, bool:AllowBot = true, bool:AllowDeath = true)
{
    if (Client < 1 || Client > MaxClients)
        return false;
    if (!IsClientConnected(Client) || !IsClientInGame(Client))
        return false;
    if (!AllowBot)
    {
        if (IsFakeClient(Client))
            return false;
    }

    if (!AllowDeath)
    {
        if (!IsPlayerAlive(Client))
            return false;
    }    
    
    return true;
}
// 获取连接数
public GetRealClientCount(inGameOnly) 
{
    new clients = 0;
    if(inGameOnly)
    {
        for( new i = 1; i <= MaxClients; i++ ) 
        {
            if(IsClientInGame( i )  && !IsFakeClient( i ))
            {
                clients++;
            }
        }            
    }
    else
    {
        for( new i = 1; i <= MaxClients; i++ ) 
        {
            if(IsClientConnected( i ) && !IsFakeClient( i ))
            {
                clients++;
            }
        }
    }
    return clients;
}
